home *** CD-ROM | disk | FTP | other *** search
/ TOS Silver 2000 / TOS Silver 2000.iso / programm / MM2_DEV / S / MYUTIL / PRGLOADE.I < prev    next >
Encoding:
Modula Implementation  |  1991-02-13  |  16.4 KB  |  538 lines

  1.  
  2. IMPLEMENTATION MODULE PrgLoader;
  3.  
  4. (*
  5.  * Mini-Version des "Loader"-Moduls von Megamax Modula-2.
  6.  *
  7.  * Dieses Modul kann nur Programme im GEMDOS-Format resident laden
  8.  * und starten, jedoch keine einzelnen Megamax-Module.
  9.  *
  10.  * In der Ausgabe 4/91 der Zeitschrift TOS finden Sie die ausführliche
  11.  * Beschreibung dieses nützlichen Programms.
  12.  *
  13.  * Hinweis/Copyright:
  14.  * ------------------
  15.  *   Die Verwendungsrechte dieses Programms und seiner Quellen in der
  16.  *   vorliegenden Version 2.0 liegt bei der Zeitschrift TOS (ICP-Verlag,
  17.  *   Vaterstetten). Ein Verkauf dieses Programms oder seiner Quellen
  18.  *   getrennt von den Zeitschriften des ICP-Verlags ist jedoch nicht
  19.  *   gestattet.
  20.  *
  21.  *   Mit Erwerb der Zeitschrift "TOS" steht es Ihnen frei, das Programm
  22.  *   zu nutzen. Das Programm ist also keine Freeware oder PD!
  23.  *   Sie dürfen das Programm verändern, jedoch nicht selbst "verbesserte"
  24.  *   Versionen dieses Programms verbreiten. Dies obliegt allein dem Urheber
  25.  *   Thomas Tempelmann.
  26.  *
  27.  *   Ich hoffe, Sie beachten diese Hinweise. Ich wäre schwer enttäuscht,
  28.  *   wenn plötzlich eine Version 2.1, die nicht von mir stammt, auf
  29.  *   dem PD- oder Raubkopiermarkt erscheint. Dann könnte dies der letzte
  30.  *   Beitrag von mir gewesen sein. Fairness und Vertrauen sind wichtig
  31.  *   für das Weiterleben dieser Form der Softwareveröffentlichung!
  32.  *
  33.  *   Für Fragen, Wünsche, Verbesserungen und Veröffentlichungen wenden
  34.  *   Sie sich bitte an den Autor:
  35.  *      Thomas Tempelmann, Nordendstr. 64, D-8000 München 40.
  36.  *
  37.  * ------------------------------------------------------------------------
  38.  *)
  39.  
  40. (*$R-,S-*)
  41.  
  42. FROM SYSTEM IMPORT CAST, WORD, ADDRESS, ADR, CADR, ASSEMBLER;
  43. FROM MOSGlobals IMPORT NameStr, PathStr, FileStr;
  44. FROM Strings IMPORT StrEqual, Upper, Assign;
  45. FROM FileNames IMPORT PathConc, SplitPath, ConcatPath;
  46. FROM Storage IMPORT ALLOCATE, DEALLOCATE;
  47. FROM MOSCtrl IMPORT ProcessID;
  48. FROM SysTypes IMPORT PtrBP;
  49. FROM SysUtil1 IMPORT BPoke;
  50. FROM SysInfo IMPORT UseStackFrame;
  51. IMPORT GEMDOS;
  52. IMPORT Block;
  53. IMPORT XBRA;
  54.  
  55. CONST   MaxPrgToLoad = 10;  (* Anzahl maximal ladbarer Programme *)
  56.  
  57.         Kennung = "PLdr";   (* XBRA-Kennung für GEMDOS-Handler *)
  58.  
  59.  
  60. TYPE    LoadRange  = [1..MaxPrgToLoad];
  61.  
  62.         PrgEntry = RECORD  (* Beschreibung für ein geladenes Programm *)
  63.                      used: BOOLEAN;
  64.                      name: NameStr;
  65.                      path: PathStr;
  66.                      basepage: PtrBP;
  67.                      currentHeapSize: LONGCARD;
  68.                      neededHeapSize: LONGCARD;
  69.                      isMM2: BOOLEAN;
  70.                      runs: SHORTCARD;
  71.                      owner: ADDRESS;
  72.                    END;
  73.  
  74. VAR     Loaded: ARRAY LoadRange OF PrgEntry; (* Liste der geladenen Programme *)
  75.         CurrentField, CurrentBasePage: ADDRESS;
  76.         TPAOffset: LONGCARD;
  77.         GemdosEntry: ADDRESS;
  78.         StackFrameOffs: SHORTCARD;
  79.  
  80. PROCEDURE Mfree (addr: ADDRESS);
  81.   VAR ok: BOOLEAN;
  82.   BEGIN
  83.     ok:= GEMDOS.Free (addr)
  84.   END Mfree;
  85.  
  86. PROCEDURE Mshrink (addr: ADDRESS; newAmount: LONGCARD);
  87.   VAR ok: BOOLEAN;
  88.   BEGIN
  89.     ok:= GEMDOS.Shrink (addr, newAmount);
  90.   END Mshrink;
  91.  
  92. PROCEDURE prgUnload (bp: PtrBP);
  93.   (*
  94.    * Gibt den Speicher eines geladenen Programms wieder frei.
  95.    *)
  96.   BEGIN
  97.     Mfree (bp^.p_env); (* Environment freigeben *)
  98.     Mfree (bp)         (* TPA / Prg. freigeben *)
  99.   END prgUnload;
  100.  
  101. PROCEDURE prgLoad (REF name: ARRAY OF CHAR; VAR result: LONGINT);
  102.   (*
  103.    * Lädt ein Programm mit der GEMDOS-Funktion "Pexec"
  104.    *)
  105.   VAR nullstring: CHAR; fullname: FileStr; ok: BOOLEAN;
  106.   BEGIN
  107.     nullstring:= 0C;
  108.     Assign (name, fullname, ok);
  109.     GEMDOS.Pexec (3, ADR (fullname), ADR (nullstring), 0, result)
  110.   END prgLoad;
  111.  
  112. PROCEDURE getLoaderResult (execRes: INTEGER; VAR myRes: LoaderResults);
  113.   (*
  114.    * IN: GEMDOS-Fehlercode
  115.    * OUT: Loader-Fehlercode
  116.    *)
  117.   BEGIN
  118.     IF (execRes = -33) OR (execRes = -34) THEN
  119.       myRes:= notFound;
  120.     ELSIF (execRes = -39) THEN
  121.       myRes:= outOfMemory;
  122.     ELSE
  123.       myRes:= badFile;
  124.     END;
  125.   END getLoaderResult;
  126.  
  127. PROCEDURE envLength (env: ADDRESS): LONGCARD;
  128.   (*
  129.    * Liefert die Länge eines Environment-Strings
  130.    *)
  131.   VAR (*$Reg*) p: POINTER TO CHAR;
  132.   BEGIN
  133.     p:= env;
  134.     WHILE p^ # 0C DO
  135.       REPEAT
  136.         INC (p)
  137.       UNTIL p^ = 0C;
  138.       INC (p)
  139.     END;
  140.     RETURN ADDRESS (p) - env + 2
  141.   END envLength;
  142.  
  143. PROCEDURE CodeSize (bp: PtrBP): LONGCARD;
  144.   (*
  145.    * Liefert Länge des statisch belegten Bereichs ohne den Heap-Bonus
  146.    *)
  147.   BEGIN
  148.     WITH bp^ DO
  149.       RETURN 256 + p_tlen + p_dlen + p_blen
  150.     END
  151.   END CodeSize;
  152.  
  153. PROCEDURE prgPrepare (bp: PtrBP; heapSize: LONGCARD): BOOLEAN;
  154.   (*
  155.    * Nimmt Anpassungen nach dem Laden eines Programms vor
  156.    *)
  157.   VAR newlen: LONGCARD; bpsize: LONGCARD;
  158.   BEGIN
  159.     (* belegten Speicher (TPA) berechnen: *)
  160.     bpsize:= LONGCARD (bp^.p_hitpa) - LONGCARD (bp);
  161.     (* benötigten Speicher berechnen: *)
  162.     newlen:= CodeSize (bp) + heapSize;
  163.     (* Haben wir genug Platz im TPA erhalten? *)
  164.     IF newlen > bpsize THEN
  165.       (* wenn nicht, dann Laden abbrechen *)
  166.       prgUnload (bp);
  167.       RETURN FALSE
  168.     END;
  169.     (* TPA auf benötigten Bereich verkleinern *)
  170.     Mshrink (bp, newlen);
  171.     bp^.p_hitpa:= ADDRESS (bp) + newlen;
  172.     RETURN TRUE
  173.   END prgPrepare;
  174.  
  175. PROCEDURE removeGemdosHdler;
  176.   (*
  177.    * Trägt den hiesigen GEMDOS-Handler (hdlGemdos) aus.
  178.    *)
  179.   (*$S-  hier ist kein Stack-Check nötig *)
  180.   VAR at: ADDRESS;
  181.   BEGIN
  182.     IF XBRA.Installed (Kennung, $84, at) THEN
  183.       XBRA.Remove (at);
  184.     END;
  185.   END removeGemdosHdler;
  186.   (*$S=  vorige Einstellung zurück *)
  187.  
  188. VAR Stack: ARRAY [1..600] OF WORD;
  189.  
  190. PROCEDURE hdlGemdos;
  191. (*
  192.  * Diese Funktion hängt im GEMDOS-TRAP-Handler und wartet darauf, daß
  193.  * das über 'CallProgram' gestartete Programm die 'Mshrink'-Funktion
  194.  * aufruft. Dann wird daraus die benötigte Heap-Größe ermittelt und
  195.  * diese Funktion wieder ausgehängt.
  196.  *)
  197.   (*$L-*)
  198.   BEGIN
  199.     ASSEMBLER
  200.         BTST.B  #5,(A7)         ; War Supervisormode aktiv ?
  201.         BNE.B   super           ; Ja, dann stehen Arg. auf SSP
  202.         MOVE.L  USP,A0
  203.         CMPI.W  #$4A,(A0)       ; Mshrink - Funktion ?
  204.         BEQ.B   hdlMshrinkUser
  205. dos     ; normale GEMDOS-Funktion ausführen
  206.         MOVE.L  GemdosEntry,A0
  207.         MOVE.L  -4(A0),A0
  208.         JMP     (A0)
  209. super   MOVE.W  StackFrameOffs,D0 ; damit es auch mit einer 68010/20/30 geht
  210.         CMPI.W  #$4A,6(A7,D0.W) ; Mshrink - Funktion ?
  211.         BNE.B   dos             ; Nein -> GEMDOS aufrufen
  212.         LEA     6(A7,D0.W),A0   ; Basis d. Argumente nach A0
  213. hdlMshrinkUser
  214.         MOVE.L  4(A0),A1        ; Argument 'addr' von Mshrink (addr, newamount)
  215.         CMPA.L  CurrentBasePage,A1 ; ist es die TPA des gesuchten Programms?
  216.         BNE     dos
  217.         MOVE.L  8(A0),D0        ; 'newamount'-Parm von Mshrink: neue TPA-Größe
  218.         MOVE.L  D0,D1
  219.         ADD.L   A1,D0
  220.         CMP.L   4(A1),D0        ; newamout > p_hitpa (alte TPA-Größe)?
  221.         BHI     noNewHi         ;  dann ist zu wenig Speicher da
  222.         MOVE.L  D0,4(A1)        ; p_hitpa in Base Page neu setzen
  223. noNewHi TST.L   UsedHeapSize
  224.         BPL     ignore          ; Heap-Größe wurde bereits ermittelt
  225.         SUB.L   TPAOffset,D1    ; Subtr. die Größe des stat. Bereichs ohne Heap
  226.         MOVE.L  D1,UsedHeapSize ; Das ist die gesuchte Heap-Größe
  227.         MOVE.L  CurrentField,A0
  228.         MOVE.L  D1,PrgEntry.neededHeapSize(A0)
  229.         CMP.L   PrgEntry.currentHeapSize(A0),D1
  230.         BCC     ignore
  231.         MOVE.L  D1,PrgEntry.currentHeapSize(A0)
  232. ignore  ; Diese Routine kann nun aus dem GEMDOS-TRAP entfernt werden
  233.         MOVE.L  A3,-(A7)
  234.         MOVE.L  A7,D0
  235.         LEA     Stack,A3
  236.         LEA     SIZE(Stack) (A3),A7
  237.         MOVE.L  D0,-(A7)
  238.         JSR     removeGemdosHdler
  239.         MOVE.L  (A7)+,A7
  240.         MOVE.L  (A7)+,A3
  241.         BRA     dos     ; Nun lassen wir endlich Mshrink ausführen
  242.     END
  243.   END hdlGemdos;
  244.   (*$L=*)
  245.  
  246.  
  247. PROCEDURE prgExec (bp: PtrBP; filename: ADDRESS; REF arg: ArgStr;
  248.                    env: ADDRESS; multi, isMM2: BOOLEAN; VAR exitcode: LONGINT);
  249.   (*
  250.    * Startet geladenes Programm.
  251.    * 'multi': TRUE heißt, daß geladenes Prg nicht nur einmal gestartet
  252.    *   werden kann und deshalb DATA-Bereich usw. gerettet werden müssen.
  253.    *)
  254.  
  255.   TYPE ptrLInt = POINTER TO LONGINT;
  256.  
  257.   VAR el, dl: LONGCARD; oldEnv, hitpa, at, envcopy, data: ADDRESS;
  258.       carrier: XBRA.Carrier; p3: ptrLInt; stackSize: LONGINT;
  259.  
  260.   BEGIN
  261.     IF multi THEN
  262.       (* Base Page- und DATA-Bereich retten *)
  263.       dl:= bp^.p_dlen + 128; (* Länge des zu rettenden Data/Basepage-Bereichs *)
  264.       ALLOCATE (data, dl);
  265.       IF data = NIL THEN
  266.         (* kein Speicherplatz mehr frei *)
  267.         exitcode:= -39;
  268.         RETURN
  269.       END;
  270.       Block.Copy (bp, 128, data); (* die ersten 128 Byte der Base Page retten *)
  271.       Block.Copy (bp^.p_dbase, bp^.p_dlen, data+128);
  272.       IF isMM2 THEN p3:= ADDRESS(bp)+(256+56); stackSize:= p3^ END;
  273.  
  274.       (* BSS löschen *)
  275.       Block.Clear (bp^.p_bbase, bp^.p_hitpa - bp^.p_bbase);
  276.     END;
  277.     
  278.     (* Commandline in die Base Page kopieren *)
  279.     Block.Copy (CADR (arg), 128, ADR (bp^.cmdline));
  280.     
  281.     IF multi THEN
  282.       (* Pfade v. Parent übernehmen *)
  283.       Block.Copy (ProcessID^+$37, 1, ADDRESS(bp)+$37);
  284.       Block.Copy (ProcessID^+$40, 16, ADDRESS(bp)+$40);
  285.     END;
  286.     
  287.     (* DTA auf Cmdline *)
  288.     bp^.p_dta:= ADR (bp^.cmdline);
  289.     
  290.     (* Environment kopieren, da Pexec dies wie so vieles *
  291.      * beim Nur-Starten fälschlicherweise nicht tut.    *)
  292.     oldEnv:= bp^.p_env;
  293.     IF multi & (env # 0) THEN
  294.       el:= envLength (env);
  295.       ALLOCATE (envcopy, el)
  296.     END;
  297.     IF multi & (env # 0) & (envcopy = NIL) THEN
  298.       (* kein Speicherplatz mehr frei *)
  299.       exitcode:= -39;
  300.     ELSE
  301.       IF multi & (env # 0) THEN
  302.         Block.Copy (env, el, envcopy);
  303.         bp^.p_env:= envcopy;
  304.       END;
  305.       
  306.       (* 'hdlGemdos' in TRAP #1 einhängen *)
  307.       XBRA.Create (carrier, Kennung, CAST (ADDRESS, hdlGemdos), GemdosEntry);
  308.       XBRA.Install (GemdosEntry, $84);
  309.       
  310.       (* Prozeß starten *)
  311.       TPAOffset:= CodeSize (bp);
  312.       CurrentBasePage:= bp;
  313.       GEMDOS.Pexec (4, filename, bp, env, exitcode);
  314.       CurrentBasePage:= NIL;
  315.       
  316.       (* 'hdlGemdos' wieder aushängen *)
  317.       removeGemdosHdler;
  318.       
  319.       IF multi & (env # 0) THEN
  320.         DEALLOCATE (envcopy, 0)  (* Kopie vom Environment wieder freigeben *)
  321.       END
  322.     END;
  323.     bp^.p_env:= oldEnv;
  324.  
  325.     IF multi THEN
  326.       (* geretteten Base Page- und DATA-Bereich zurückkopieren *)
  327.       hitpa:= bp^.p_hitpa;
  328.       Block.Copy (data, 128, bp);
  329.       bp^.p_hitpa:= hitpa;
  330.       IF isMM2 THEN p3^:= stackSize END;
  331.       Block.Copy (data+128, bp^.p_dlen, bp^.p_dbase);
  332.       DEALLOCATE (data, 0); (* gesamten DATA-Bereich wieder freigeben *)
  333.     END
  334.   END prgExec;
  335.  
  336.  
  337. PROCEDURE isLoaded (REF nameWOpath: ARRAY OF CHAR;
  338.                     VAR index: LoadRange): BOOLEAN;
  339.   (*
  340.    * Liefert TRUE, wenn "nameWOpath" geladen ist.
  341.    * Der übergebene Name darf keinen Pfad enthalten.
  342.    * 'index' enthält den Feldindex in "Loaded", wenn Prg. geladen ist,
  343.    * ansonsten liefert es den Index auf ein unbenutztes Feld in "Loaded".
  344.    *)
  345.  
  346.   VAR c: LoadRange; free: BOOLEAN;
  347.  
  348.   BEGIN
  349.     free:= FALSE;
  350.     FOR c:= MIN (LoadRange) TO MAX (LoadRange) DO
  351.       WITH Loaded[c] DO
  352.         IF used THEN
  353.           IF StrEqual (nameWOpath, name) THEN
  354.             (* wir haben ihn gefunden *)
  355.             index:= c;
  356.             RETURN TRUE
  357.           END
  358.         ELSE
  359.           IF NOT free THEN
  360.             (* ersten freien Eintrag merken *)
  361.             index:= c;
  362.             free:= TRUE
  363.           END
  364.         END
  365.       END
  366.     END;
  367.     RETURN FALSE
  368.   END isLoaded;
  369.  
  370.  
  371. PROCEDURE LoadProgram (    filename: ARRAY OF CHAR;
  372.                            heapSize: LONGCARD;
  373.                        VAR result  : LoaderResults);
  374. (*
  375.  * Lädt ein Programm mit der angegeben Heap-Größe.
  376.  * Ergebnis in 'result'.
  377.  *)
  378.  
  379.   TYPE ptrStr = POINTER TO ARRAY [0..19] OF CHAR;
  380.        ptrCard= POINTER TO CARDINAL;
  381.  
  382.   VAR prgname: NameStr; prgpath: PathStr; index: LoadRange;
  383.       ploadres: LONGINT; bp: ADDRESS; p1: ptrStr; p2: ptrCard;
  384.  
  385.   BEGIN
  386.     Upper (filename);
  387.     SplitPath (filename, prgpath, prgname);
  388.     
  389.     (* Programm schon geladen? Dann Abbruch *)
  390.     IF isLoaded (prgname, index) THEN
  391.       result:= alreadyLoaded;
  392.       RETURN
  393.     END;
  394.     
  395.     (* Programm laden *)
  396.     prgLoad (filename, ploadres);
  397.     IF ploadres < 0 THEN
  398.       (* Fehler beim Laden aufgetreten *)
  399.       getLoaderResult (SHORT (ploadres), result);
  400.       RETURN
  401.     END;
  402.     
  403.     (* Programm im Speicher vorbereiten *)
  404.     bp:= PtrBP (ploadres);
  405.     IF NOT prgPrepare (bp, heapSize) THEN
  406.       (* Speicher reicht nicht *)
  407.       prgUnload (bp);
  408.       result:= outOfMemory;
  409.       RETURN
  410.     END;
  411.     
  412.     (* Programm erfolgreich geladen. Nun eintragen *)
  413.     WITH Loaded[index] DO
  414.       used:= TRUE;
  415.       name:= prgname;
  416.       path:= prgpath;
  417.       basepage:= bp;
  418.       neededHeapSize:= LONGCARD (-1);  (* noch undefiniert *)
  419.       currentHeapSize:= heapSize;
  420.       runs:= 0;
  421.       owner:= ProcessID^;
  422.       p1:= ADDRESS (bp) + (256 + 18); p2:= ADDRESS (bp) + (256 + 38);
  423.       isMM2:= StrEqual ("Megamax Modula-2 V2", p1^) AND (p2^ = 4)
  424.     END;
  425.     result:= noError;
  426.   END LoadProgram;
  427.  
  428.  
  429. PROCEDURE UnLoadProgram (    filename: ARRAY OF CHAR;
  430.                          VAR result  : LoaderResults);
  431. (*
  432.  * Gibt geladenes Programm frei.
  433.  * Ergebnis in 'result'.
  434.  *)
  435.  
  436.   VAR prgname: NameStr; prgpath: PathStr; index: LoadRange;
  437.  
  438.   BEGIN
  439.     Upper (filename);
  440.     SplitPath (filename, prgpath, prgname);
  441.     IF isLoaded (prgname, index) THEN
  442.       WITH Loaded[index] DO
  443.         prgUnload (basepage);
  444.         used:= FALSE
  445.       END;
  446.       result:= noError
  447.     ELSE
  448.       result:= notFound
  449.     END
  450.   END UnLoadProgram;
  451.  
  452.  
  453. PROCEDURE Arg (REF in: ARRAY OF CHAR): ArgStr;
  454.   (*
  455.    * Erzeugt die GEMDOS-Cmdline für Pexec() aus einem Modula-String.
  456.    *)
  457.   VAR l: CARDINAL; out: ArgStr;
  458.   BEGIN
  459.     l:= LENGTH (in);
  460.     IF l > 125 THEN l:= 125 END;
  461.     Block.Clear (ADR (out), SIZE (out));    (* Cmdline zuerst löschen *)
  462.     Block.Copy (CADR (in), l, ADR (out)+1); (* Arg. eintragen *)
  463.     BPoke (ADR (out), l);                   (* Länge in 1.Byte eintragen *)
  464.     RETURN out
  465.   END Arg;
  466.  
  467.  
  468. PROCEDURE CallProgram (    filename   : ARRAY OF CHAR;
  469.                        REF argLine    : ArgStr;
  470.                            environment: ADDRESS;
  471.                        VAR exitCode   : LONGINT);
  472. (*
  473.  * Startet Programm, auch ungeladen. 'args' enthält die Command Line als
  474.  * normalen Modula-String.
  475.  * Ergebnis in 'exitCode'.
  476.  *)
  477.  
  478.   VAR prgname: NameStr; prgpath: PathStr; index: LoadRange;
  479.       bp: ADDRESS; fullname: FileStr; ok: BOOLEAN;
  480.  
  481.   BEGIN
  482.     CurrentField:= NIL;
  483.     UsedHeapSize:= LONGCARD (-1);
  484.     Upper (filename);
  485.     SplitPath (filename, prgpath, prgname);
  486.     IF isLoaded (prgname, index) THEN
  487.       (* geladenes Prg starten *)
  488.       CurrentField:= ADR (Loaded[index]);
  489.       WITH Loaded[index] DO
  490.         ConcatPath (path, name, fullname);
  491.         INC (runs);
  492.         prgExec (basepage, ADR (fullname), argLine, environment, TRUE, isMM2,
  493.                  exitCode)
  494.       END
  495.     ELSE
  496.       (* Programm laden & starten, und zwar getrennt, um 'HeapSize'
  497.        * ermitteln zu können. *)
  498.       prgLoad (filename, exitCode);
  499.       IF exitCode < 0 THEN (* Fehler beim Laden aufgetreten *) RETURN END;
  500.       bp:= ADDRESS (exitCode); (* Base Page merken *)
  501.       Assign (filename, fullname, ok);
  502.       prgExec (bp, ADR (fullname), argLine, environment, FALSE, FALSE,
  503.                exitCode);
  504.       prgUnload (bp);
  505.     END
  506.   END CallProgram;
  507.  
  508. PROCEDURE ProgramLoaded (filename: ARRAY OF CHAR): BOOLEAN;
  509. (*
  510.  * Liefert TRUE, wenn Programm geladen ist
  511.  *)
  512.   VAR prgname: NameStr; prgpath: PathStr; index: LoadRange;
  513.   BEGIN
  514.     Upper (filename);
  515.     SplitPath (filename, prgpath, prgname);
  516.     RETURN isLoaded (prgname, index);
  517.   END ProgramLoaded;
  518.  
  519. (*$H+*)
  520. PROCEDURE QueryLoaded (call: QueryPrgProc);
  521.   VAR c: CARDINAL;
  522.   BEGIN
  523.     FOR c:= MIN (LoadRange) TO MAX (LoadRange) DO
  524.       WITH Loaded[c] DO
  525.         IF used THEN
  526.           IF NOT call (PathConc (path, name), runs,
  527.                        currentHeapSize, neededHeapSize) THEN
  528.             RETURN
  529.           END
  530.         END
  531.       END
  532.     END
  533.   END QueryLoaded;
  534.  
  535. BEGIN
  536.   IF UseStackFrame () THEN StackFrameOffs:= 2 ELSE StackFrameOffs:= 0 END;
  537. END PrgLoader.
  538.